/******************************************************************************
 * (c) 2011 Komersi Software                                                  *
 * www.komersisoftware.com                                                    *
 *                                                                            *
 * This file is part of Tadah                                                 *
 * Licensed under GNU General Public License v2.0                             *
 * Check LICENSE.TXT for more information                                     *
 ******************************************************************************/
 
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "tableinfo.h"
#include "validation.h"
#include "column.h"
#include "engine.h"
#include "primaryindex.h"

#ifndef _MSC_VER
inline
#endif
static void set_eof(FILE *file)
{
	fclose(file);
}

static int primary_index_count(table_info_t *table_info)
{
	ddl_column_t *cur = table_info->column_list;
	int count = 0;

	while (cur != NULL)
	{
		if (cur->primary_index == IsPrimaryIndex)
		{
			count++;
		}

		cur = cur->next;
	}

	return count;
}

ddl_column_t *get_primary_index(table_info_t *table)
{
	ddl_column_t *cur = NULL;

	if (table == NULL)
	{
		return NULL;
	}

	if (table->column_list == NULL)
	{
		return NULL;
	}

	if (primary_index_count(table) != 1)
	{
		return NULL;
	}

	cur = table->column_list;

	while (cur != NULL)
	{
		if (cur->primary_index == IsPrimaryIndex)
		{
			return cur;
		}

		cur = cur->next;
	}

	return NULL;
}

int set_primary_index(table_info_t *table, ddl_column_t *column)
{
	ddl_column_t *cur = NULL;
	_Bool found = FALSE;

	if (table == NULL)
	{
		return FALSE;
	}

	if (column == NULL)
	{
		return FALSE;
	}

	cur = table->column_list;
	while (cur != NULL)
	{
		if (cur == column)
		{
			cur->primary_index = IsPrimaryIndex;
			found = TRUE;
		}
		else
		{
			cur->primary_index = IsNotPrimaryIndex;
		}

		cur = cur->next;
	}

	return found;
}

table_info_t *new_table_info(char *name)
{
    table_info_t *table = NULL;

    if (is_table_name_valid(name))
    {
        table = malloc(sizeof(table_info_t));
        memset(table, 0, sizeof(table_info_t));

        strcpy(table->name, name);
        strcpy(table->table_filename, generate_filename_table(name));
        strcpy(table->ddl_filename, generate_filename_ddl(name));
        strcpy(table->primary_index_filename, generate_filename_primary_index(name));

        table->column_list = NULL;
        table->primary_index = NULL;
    }

    return table;
}

primary_index_info_t *load_primary_index(table_info_t *table)
{
	ddl_column_t *column = NULL;
	primary_index_info_t *index_list = NULL;
	FILE *file = NULL;
	void *value = NULL;
	long file_size;
	long index_val;
	int error = FALSE;

	if (table == NULL)
	{
		return NULL;
	}

	column = get_primary_index(table);
	if (column == NULL)
	{
		return NULL;
	}

	file = fopen(table->primary_index_filename, "rb");
    if (file == NULL)
    {
    	return NULL;
    }

    fseek(file , 0 , SEEK_END);
    file_size = ftell(file);
    rewind(file);

    while (!feof(file))
    {
    	if (ftell(file) >= file_size)
    	{
    		error = FALSE;
    		break;
    	}

    	value = NULL;

    	switch (column->type)
    	{
    	case Int:
    		value = calloc(sizeof(int), 1);
    		if (fread(value, sizeof(int), 1, file) != 1) // TODO crash here
    		{
    			error = TRUE;
    		}
    		break;
    	case Char:
    		value = calloc(sizeof(char), column->size + 1);
    		if (fread(value, sizeof(char), column->size + sizeof(char), file) != column->size + sizeof(char))
    		{
    			error = TRUE;
    		}
    		break;
    	}

    	if (error)
    	{
    		break;
    	}

    	if (fread(&index_val, sizeof(long), 1, file) != 1)
    	{
    		error = TRUE;
    		break;
    	}

    	primary_index_list_add(&index_list, new_primary_index_info(column, index_val, value));
    }

    set_eof(file);

    if (error)
    {
    	dispose_primary_index_list(&index_list);
    	return NULL;
    }

	return index_list;
}

table_info_t *load_table_info(char *name)
{
    table_info_t *table = new_table_info(name);

    if (table == NULL)
    {
    	return NULL;
    }

    table->column_list = load_ddl_list(table);
    if (table->column_list == NULL)
    {
    	dispose_table_info(&table);
    	return NULL;
    }

    table->primary_index = load_primary_index(table);
    // TODO need a signature to the file so it will never be empty
    // TODO create dat file here
    /*if (table->primary_index == NULL)
    {
    	dispose_table_info(&table);
    	return NULL;
    }*/

    return table;
}

#ifndef _MSC_VER
inline
#endif
void dispose_table_info(table_info_t **object)
{
	dispose_column_list(&((*object)->column_list));
	dispose_primary_index_list(&((*object)->primary_index));

    free(*object);
    *object = NULL;
}

static int create_ddl_file(table_info_t *table_info)
{
	FILE *ddl_file = NULL;
	ddl_column_t *column_cursor = table_info->column_list;

	ddl_file = fopen(table_info->ddl_filename, "wb");
	if (ddl_file == NULL)
	{
		return FAILURE;
	}

	while (column_cursor != NULL)
	{
		if (fwrite(column_cursor->name, sizeof(char), COLUMN_NAME_LENGTH + sizeof(char),ddl_file) <= 0)
		{
			set_eof(ddl_file);
			return FAILURE;
		}

		if (fwrite(&(column_cursor->type), sizeof(data_type_t), 1, ddl_file) <= 0)
		{
			set_eof(ddl_file);
			return FAILURE;
		}

		if (fwrite(&(column_cursor->size), sizeof(int), 1, ddl_file) <= 0)
		{
			set_eof(ddl_file);
			return FAILURE;
		}

		if (fwrite(&(column_cursor->primary_index), sizeof(primary_index_type_t), 1, ddl_file) <= 0)
		{
			set_eof(ddl_file);
			return FAILURE;
		}

		column_cursor = column_cursor->next;
	}

	set_eof(ddl_file);

	return SUCCESS;
}

static int create_primary_index_file(table_info_t *table_info)
{
	FILE *file = NULL;

	file = fopen(table_info->primary_index_filename, "wb");

	if (file == NULL)
	{
		return FAILURE;
	}

	fclose(file);
	return SUCCESS;
}

int create_table(table_info_t *table_info)
{
	// TODO: check if files already exist and return FAILURE
	// TODO: if a step failed, previous steps must be rolled back

	if (primary_index_count(table_info) != 1)
	{
		return FAILURE;
	}

	if (!create_ddl_file(table_info))
	{
		return FAILURE;
	}

	if (!create_primary_index_file(table_info))
	{
		return FAILURE;
	}

	return SUCCESS;
}
